﻿/******************************************************************************
 * Copyright (C) 671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef NODECPP_FOUNDATION_BYTEBUFFER_H_
#define NODECPP_FOUNDATION_BYTEBUFFER_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <exception>
#include <NodeCpp/Macros.h>
#include <NodeCpp/ByteConverter.h>

namespace NodeCpp
{
    //-------------------------------------------------------------------------
	class ByteBufferException : public std::exception
	{
	public:
		ByteBufferException(bool _Add, std::size_t _Pos,
			std::size_t _Size, std::size_t _OpSize)
			: Add_(_Add), Pos_(_Pos), Size_(_Size), OpSize_(_OpSize)
		{
			_PrintPosError();
		}

		const char* what(void) const throw ();

	private:
		const static int WHAT_SIZE = 128;

		void _PrintPosError();

		bool		Add_;       // 是否向缓存添加数据
		std::size_t	Pos_;       // 操作的位置
		std::size_t	Size_;      // 当前缓存大小
		std::size_t	OpSize_;    // 操作的数据大小

		char	What_[WHAT_SIZE];
	};

	inline const char *ByteBufferException::what(void) const throw()
	{
		return What_;
	}


    //-------------------------------------------------------------------------
	class ByteBuffer
	{
	public:
		typedef std::vector<std::uint8_t>::size_type size_type;
        typedef ByteBuffer  Self;

        static const std::size_t DEFAULT_SIZE = 0x200;
        static const std::size_t MAX_SIZE = 0x1000000;

	public:
        ByteBuffer(void)
			: RPos_(0)
			, WPos_(0)
			, Storage_()
		{
            Storage_.reserve(DEFAULT_SIZE);
		}

        explicit ByteBuffer(size_type _Size)
			: RPos_(0)
			, WPos_(0)
		{
			Storage_.reserve(_Size);
		}

        ByteBuffer(const ByteBuffer &_Buf)
			: RPos_(_Buf.RPos_)
			, WPos_(_Buf.WPos_)
			, Storage_(_Buf.Storage_)
		{

		}

        virtual ~ByteBuffer(void)
		{

		}

		void Clear(void) {
			Storage_.clear();
			RPos_ = WPos_ = 0;
		}

		void Resize(size_type _Nsize, bool _Wnew = false) {
			Storage_.resize(_Nsize);
			RPos_ = 0;
			WPos_ = _Wnew ? Storage_.size() : 0;
		}

		size_type size(void) const {
			return Storage_.size();
		}

		const std::uint8_t* contents(size_type _Index = 0) const {
			NODECPP_ASSERT(_Index >= 0 && _Index < size());
			return &Storage_[_Index];
		}
		std::uint8_t* contents(size_type _Index = 0) {
			NODECPP_ASSERT(_Index >= 0 && _Index < size());
			return &Storage_[_Index];
		}

		size_type rpos(void) const {
			return RPos_;
		}
		size_type wpos(void) const {
			return WPos_;
		}

		void rpos(size_type _Pos) {
			RPos_ = _Pos;
		}
		void wpos(size_type _Pos) {
			WPos_ = _Pos;
		}

	public:
		//-------------------------------------------------------------------------
        Self& operator<<(std::uint8_t _X) {
			Append<std::uint8_t>(_X);
			return *this;
		}
        Self& operator<<(std::uint16_t _X) {
			Append<std::uint16_t>(_X);
			return *this;
		}
        Self& operator<<(std::uint32_t _X) {
			Append<std::uint32_t>(_X);
			return *this;
		}
        Self& operator<<(std::uint64_t _X) {
			Append<std::uint64_t>(_X);
			return *this;
		}
        Self& operator<<(float _X) {
			Append(_X);
			return *this;
		}
        Self& operator<<(const char* _X) {
			Append(_X, strlen(_X));
			*this << (std::uint8_t)0;
			return *this;
		}
        Self& operator<<(const std::string& _X) {
			Append(_X.c_str(), _X.length());
			*this << (std::uint8_t)0;
			return *this;
		}

		//-------------------------------------------------------------------------
        Self& operator>>(std::uint8_t& _X) {
			_X = Read<std::uint8_t>();
			return *this;
		}
        Self& operator>>(std::uint16_t& _X) {
			_X = Read<std::uint16_t>();
			return *this;
		}
        Self& operator>>(std::uint32_t& _X) {
			_X = Read<std::uint32_t>();
			return *this;
		}
        Self& operator>>(std::uint64_t& _X) {
			_X = Read<std::uint64_t>();
			return *this;
		}
        Self& operator>>(std::string& _Value) {
			_Value.clear();
			while (RPos_ < size())
			{
				char c = Read<char>();
				if (c == 0)
				{
					break;
				}
				_Value += c;
			}
			return *this;
		}
		
        //-------------------------------------------------------------------------
		std::uint8_t operator[](size_type _Index) {
			return (Storage_[_Index]);
		}

		void Append(const char* _Src, size_type _Size) {
			if (_Size == 0) {
				return;
			}

			if ((_Size + WPos_) > MAX_SIZE) {
				throw ByteBufferException(true, WPos_, size(), _Size);
			}

			if (size() < (_Size + WPos_)) {
				Storage_.resize(_Size + WPos_);
			}

			memcpy(&Storage_[WPos_], _Src, _Size);
			WPos_ += _Size;
		}

		void Append(const std::uint8_t* _Src, size_type _Size) {
			Append((const char*)_Src, _Size);
		}

		void Append(const Self& _Bbuf) {
			Append(_Bbuf.contents(), _Bbuf.size());
		}

		void Read(std::uint8_t* _Dest, size_type _Size) {
			if ((RPos_ + _Size) > size())
			{
				throw ByteBufferException(false, RPos_, size(), _Size);
			}
			memcpy(_Dest, &Storage_[RPos_], _Size);
			RPos_ += _Size;
		}

		template<typename T>
		void Put(size_t _Pos, T& _X) {
			ByteConverter::EndianConvert(_X);
			Put(_Pos, (std::uint8_t*)&_X, sizeof(T));
		}

		void Put(size_type _Pos, std::uint8_t *_Ptr, std::size_t _Size) {
			if ((_Pos + _Size) > size()) {
				throw ByteBufferException(true, _Pos, _Size, size());
			}
			memcpy(&Storage_[_Pos], _Ptr, _Size);
		}

		template <typename T> T Read(void) {
			T _R = Read<T>(RPos_);
			RPos_ += sizeof(T);
			return _R;
		}

		std::string Dump(void);

	protected:
		template <typename T> T Read(size_t _Pos) const {
			if (_Pos + sizeof(T) > size()) {
				throw ByteBufferException(false, _Pos, size(), sizeof(T));
			}
			T _Val = *((T const*)&Storage_[_Pos]);
			ByteConverter::EndianConvert(_Val);
			return _Val;
		}

		template<typename T>
		void Append(T _X) {
			Append((const char*)&_X, sizeof(T));
		}

	protected:
		size_type                       RPos_;      // 当前读取位置
		size_type                       WPos_;      // 当前写入位置
		std::vector<std::uint8_t>       Storage_;   // 缓存
	};
}

#endif /* NODECPP_FOUNDATION_BYTEBUFFER_H_ */
